import React, {
  ButtonHTMLAttributes,
  AnchorHTMLAttributes,
  PropsWithChildren,
  ReactNode,
  useMemo,
} from "react";
import styled from "styled-components";
import { color, typography } from "../shared/styles";
import { darken, rgba, opacify } from "polished";
import { easing } from "../shared/animation";

export type AppearancesTypes = keyof typeof APPEARANCES;

type btnType =
  | "primary"
  | "primaryOutline"
  | "secondary"
  | "secondaryOutline"
  | "tertiary"
  | "outline"
  | "inversePrimary"
  | "inverseSecondary"
  | "inverseOutline";

type AppearancesObj = {
  [key in btnType]: btnType;
};

export const APPEARANCES: AppearancesObj = {
  primary: "primary",
  primaryOutline: "primaryOutline",
  secondary: "secondary",
  secondaryOutline: "secondaryOutline",
  tertiary: "tertiary",
  outline: "outline",
  inversePrimary: "inversePrimary",
  inverseSecondary: "inverseSecondary",
  inverseOutline: "inverseOutline",
};

export type SizesTypes = keyof typeof SIZES;
type sizeType = "small" | "medium";
type sizeObj = {
  [key in sizeType]: sizeType;
};
export const SIZES: sizeObj = {
  small: "small",
  medium: "medium",
};

export const btnpadding: { small: string; medium: string } = {
  small: "8px 16px",
  medium: "13px 20px",
};

export interface CustormButtonProps {
  /** 是否禁用 */
  disabled?: boolean;
  /** 是否加载中 */
  isLoading?: boolean;
  /** 是否是a标签 */
  isLink?: boolean;
  /** 是否替换加载中文本 */
  loadingText?: ReactNode;
  /** 按钮大小 */
  size?: SizesTypes;
  /** 按钮类型 */
  appearance?: AppearancesTypes;
  /** 无效点击 */
  isUnclickable?: boolean;
}

export type ButtonProps = CustormButtonProps &
  AnchorHTMLAttributes<HTMLAnchorElement> &
  ButtonHTMLAttributes<HTMLButtonElement>;

export const Text = styled.span`
  display: inline-block;
  vertical-align: top;
`;

export const Loading = styled.span`
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  opacity: 0;
`;

export const StyledButton = styled.button<ButtonProps>`
  border: 0;
  border-radius: 3em;
  cursor: pointer;
  display: inline-block;
  overflow: hidden;
  padding: ${(props) =>
    props.size === SIZES.small ? "8px 16px" : "13px 20px"};
  position: relative;
  text-align: center;
  text-decoration: none;
  transition: all 150ms ease-out;
  transform: translate3d(0,0,0);
  vertical-align: top;
  white-space: nowrap;
  user-select: none;
  opacity: 1;
  margin: 0;
  background: transparent;


  font-size: ${(props) =>
    props.size === SIZES.small ? typography.size.s1 : typography.size.s2}px;
  font-weight: ${typography.weight.extrabold};
  line-height: 1;

  ${(props) =>
    !props.isLoading &&
    `
      &:hover {
        transform: translate3d(0, -2px, 0);
        box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
      }

      &:active {
        transform: translate3d(0, 0, 0);
      }

      &:focus {
        box-shadow: ${rgba(color.primary, 0.4)} 0 1px 9px 2px;
        outline: none;
      }

      &:focus:hover {
        box-shadow: ${rgba(color.primary, 0.2)} 0 8px 18px 0px;
      }
    `}

  ${Text} {
    transform: scale3d(1,1,1) translate3d(0,0,0);
    transition: transform 700ms ${easing.rubber};
    opacity: 1;
  }

  ${Loading} {
    transform: translate3d(0, 100%, 0);
  }

  ${(props) =>
    props.disabled &&
    `
      cursor: not-allowed !important;
      opacity: 0.5;
      &:hover {
        transform: none;
      }
    `}

  ${(props) =>
    props.isUnclickable &&
    `
      cursor: default !important;
      pointer-events: none;
      &:hover {
        transform: none;
      }
    `}

  ${(props) =>
    props.isLoading &&
    `
      cursor: progress !important;
      opacity: 0.7;

      ${Loading} {
        transition: transform 700ms ${easing.rubber};
        transform: translate3d(0, -50%, 0);
        opacity: 1;
      }

      ${Text} {
        transform: scale3d(0, 0, 1) translate3d(0, -100%, 0);
        opacity: 0;
      }

      &:hover {
        transform: none;
      }
    `}



  ${(props) =>
    props.appearance === APPEARANCES.primary &&
    `
      background: ${color.primary};
      color: ${color.lightest};

      ${
        !props.isLoading &&
        `
          &:hover {
            background: ${darken(0.05, color.primary)};
          }
          &:active {
            box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
          }
          &:focus {
            box-shadow: ${rgba(color.primary, 0.4)} 0 1px 9px 2px;
            outline: none;
          }
          &:focus:hover {
            box-shadow: ${rgba(color.primary, 0.2)} 0 8px 18px 0px;
          }
        `
      }
    `}

  ${(props) =>
    props.appearance === APPEARANCES.secondary &&
    `
      background: ${color.secondary};
      color: ${color.lightest};

      ${
        !props.isLoading &&
        `
          &:hover {
            background: ${darken(0.05, color.secondary)};
          }
          &:active {
            box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
          }
          &:focus {
            box-shadow: ${rgba(color.secondary, 0.4)} 0 1px 9px 2px;
            outline: none;
          }
          &:focus:hover {
            box-shadow: ${rgba(color.secondary, 0.2)} 0 8px 18px 0px;
          }
        `
      }
    `}

  ${(props) =>
    props.appearance === APPEARANCES.tertiary &&
    `
      background: ${color.tertiary};
      color: ${color.darkest};

      ${
        !props.isLoading &&
        `
          &:hover {
            background: ${darken(0.05, color.tertiary)};
          }
          &:active {
            box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
          }
          &:focus {
            box-shadow: ${rgba(color.darkest, 0.15)} 0 1px 9px 2px;
            outline: none;
          }
          &:focus:hover {
            box-shadow: ${rgba(color.darkest, 0.05)} 0 8px 18px 0px;
          }
        `
      }
    `}

  ${(props) =>
    props.appearance === APPEARANCES.outline &&
    `
      box-shadow: ${opacify(0.05, color.border)} 0 0 0 1px inset;
      color: ${color.dark};
      background: transparent;

      ${
        !props.isLoading &&
        `
          &:hover {
            box-shadow: ${opacify(0.3, color.border)} 0 0 0 1px inset;
          }

          &:active {
            background: ${opacify(0.05, color.border)};
            box-shadow: transparent 0 0 0 1px inset;
            color: ${color.darkest};
          }

          &:active:focus:hover {
            ${
              /* This prevents the semi-transparent border from appearing atop the background */ ""
            }
            background: ${opacify(0.05, color.border)};
            box-shadow:  ${rgba(color.darkest, 0.15)} 0 1px 9px 2px;
          }

          &:focus {
            box-shadow: ${opacify(0.05, color.border)} 0 0 0 1px inset, 
            ${rgba(color.darkest, 0.15)} 0 1px 9px 2px;
            outline: none;
          }
          &:focus:hover {
            box-shadow: ${opacify(0.05, color.border)} 0 0 0 1px inset, 
            ${rgba(color.darkest, 0.05)} 0 8px 18px 0px;
          }
        `
      };
    `};

    ${(props) =>
      props.appearance === APPEARANCES.primaryOutline &&
      `
        box-shadow: ${color.primary} 0 0 0 1px inset;
        color: ${color.primary};

        &:hover {
          box-shadow: ${color.primary} 0 0 0 1px inset;
          background: transparent;
        }

        &:active {
          background: ${color.primary};
          box-shadow: ${color.primary} 0 0 0 1px inset;
          color: ${color.lightest};
        }
        &:focus {
          box-shadow: ${color.primary} 0 0 0 1px inset, ${rgba(
        color.primary,
        0.4
      )} 0 1px 9px 2px;
          outline: none;
        }
        &:focus:hover {
          box-shadow: ${color.primary} 0 0 0 1px inset, ${rgba(
        color.primary,
        0.2
      )} 0 8px 18px 0px;
        }
      `};

    ${(props) =>
      props.appearance === APPEARANCES.secondaryOutline &&
      `
        box-shadow: ${color.secondary} 0 0 0 1px inset;
        color: ${color.secondary};

        &:hover {
          box-shadow: ${color.secondary} 0 0 0 1px inset;
          background: transparent;
        }

        &:active {
          background: ${color.secondary};
          box-shadow: ${color.secondary} 0 0 0 1px inset;
          color: ${color.lightest};
        }
        &:focus {
          box-shadow: ${color.secondary} 0 0 0 1px inset,
            ${rgba(color.secondary, 0.4)} 0 1px 9px 2px;
          outline: none;
        }
        &:focus:hover {
          box-shadow: ${color.secondary} 0 0 0 1px inset,
            ${rgba(color.secondary, 0.2)} 0 8px 18px 0px;
        }
      `};

      ${(props) =>
        props.appearance === APPEARANCES.inversePrimary &&
        `
          background: ${color.lightest};
          color: ${color.primary};

          ${
            !props.isLoading &&
            `
              &:hover {
                background: ${color.lightest};
              }
              &:active {
                box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
              }
              &:focus {
                box-shadow: ${rgba(color.primary, 0.4)} 0 1px 9px 2px;
                outline: none;
              }
              &:focus:hover {
                box-shadow: ${rgba(color.primary, 0.2)} 0 8px 18px 0px;
              }
          `
          }
      `}

      ${(props) =>
        props.appearance === APPEARANCES.inverseSecondary &&
        `
          background: ${color.lightest};
          color: ${color.secondary};

          ${
            !props.isLoading &&
            `
              &:hover {
                background: ${color.lightest};
              }
              &:active {
                box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
              }
              &:focus {
                box-shadow: ${rgba(color.secondary, 0.4)} 0 1px 9px 2px;
                outline: none;
              }
              &:focus:hover {
                box-shadow: ${rgba(color.secondary, 0.2)} 0 8px 18px 0px;
              }
          `
          }
      `}

      ${(props) =>
        props.appearance === APPEARANCES.inverseOutline &&
        `
          box-shadow: ${color.lightest} 0 0 0 1px inset;
          color: ${color.lightest};

          &:hover {
            box-shadow: ${color.lightest} 0 0 0 1px inset;
            background: transparent;
          }

          &:active {
            background: ${color.lightest};
            box-shadow: ${color.lightest} 0 0 0 1px inset;
            color: ${color.darkest};
          }
          &:focus {
            box-shadow: ${color.lightest} 0 0 0 1px inset,
              ${rgba(color.darkest, 0.4)} 0 1px 9px 2px;
            outline: none;
          }
          &:focus:hover {
            box-shadow: ${color.lightest} 0 0 0 1px inset,
              ${rgba(color.darkest, 0.2)} 0 8px 18px 0px;
          }
      `};

`;

function Button(props: PropsWithChildren<ButtonProps>) {
  const { isLoading, loadingText, isLink, children } = props;
  const buttonInner = (
    <>
      <Text>{children}</Text>
      {isLoading && <Loading>{loadingText || "Loading..."}</Loading>}
    </>
  );
  const btnType = useMemo(() => {
    if (isLink) {
      return "a";
    }
  }, [isLink]);

  return (
    <StyledButton as={btnType} {...props}>
      {buttonInner}
    </StyledButton>
  );
}

Button.defaultProps = {
  isLoading: false,
  loadingText: null,
  isLink: false,
  appearance: APPEARANCES.tertiary,
  isDisabled: false,
  isUnclickable: false,
  containsIcon: false,
  size: SIZES.medium,
  ButtonWrapper: undefined,
};

export default Button;
